#include "stdafx.h"
#include "game_map_mover.hpp"
#include "game_graph.hpp"
#include "actor_manager.hpp"
#include <pantheios/inserters/integer.hpp>
#include <boost/bind.hpp>

namespace FndGame2D {
  using namespace boost ;
  const std::string game_map_mover::SET_MOVE_INIT_POS("set_move_init_pos") ;
  const std::string game_map_mover::BIND_MAP("bind_map") ;
  game_map_mover::game_map_mover(float move_speed,
				 const std::string& name, int draw_level,
				 const mover::position_type& p,
				 float angle, 
				 game_graph* g_g) :
    quad_actor(name, draw_level, p, angle) ,
    m_graph(g_g),
    m_current_move(0),
    m_current_move_time(0.0f),
    m_move_speed(move_speed),
    m_max_step(4){
    message_handler.add_handle(SET_MOVE_INIT_POS,
			       boost::bind(&game_map_mover::handle_init_move_state_message,
					   this, _1)) ;
    message_handler.add_handle(BIND_MAP, 
			       boost::bind(&game_map_mover::handle_bind_map_message,
					   this, _1)) ;
    if(m_graph) m_graph->add_buddy(this) ;

  }
  bool game_map_mover::handle_bind_map_message(const normal_thinker_message_type& msg) {
    try {
      game_graph* old_graph = m_graph ;
      m_graph = any_cast<game_graph*>(msg.param) ;
      if(m_graph) {
	old_graph->remove_buddy(this) ;
	m_graph->add_buddy(this) ;
      }
      return true ;
    } catch(bad_any_cast& /* e */) {
      pantheios::log_DEBUG("ex :", msg.sender, " ", msg.receiver, " ", msg.msg, "\n") ;
      return false ;
    }
  }

  bool game_map_mover::handle_init_move_state_message(const normal_thinker_message_type& msg) {
    if(!m_graph) {
      pantheios::log_DEBUG("game map is not valid ", msg.sender, " -> ", msg.msg) ;
      return false ;
    } else {
      try {
	m_current_move = boost::any_cast<size_t>(msg.param) ;
	m_moves.clear() ;
	m_pos_id = -1 ;
	for( ;m_current_move != m_graph->get_processors()[m_current_move] ; m_current_move = m_graph->get_processors()[m_current_move]) {
	  m_moves.push_back(m_current_move) ;
	}
	if(!m_moves.empty()) {
	  m_pos_id = 0 ;
	  std::reverse(m_moves.begin(), m_moves.end()) ; 
	}
      
	thinker_manager* mgr = get_property<thinker_manager*>(thinker_manager::HAS_MANAGER, (thinker_manager*)0) ;
	if(mgr) {
	  mgr->handle_message(make_message(name(), m_graph->name(), 0.0f,
					   m_graph->FIX_ROAD, true)) ;
	  unsigned long id = create_connection_id() ;
	  sigc::connection con = updater2.connect
	    (sigc::bind
	     (sigc::mem_fun(this, &game_map_mover::update_move), id)) ;
	  add_connection(id, con) ;
	  return true ;
	} else {
	  pantheios::log_ERROR("cound not find thinker_manager\n") ;
	}
      } catch(boost::bad_any_cast& e) {
	pantheios::log_DEBUG("could not cast ", e) ;
	return false ;
      }
    }
  }

  void game_map_mover::update_move(float time_elapsed, unsigned long id) {
    if(!m_graph) {
      remove_connection(id) ;
      return ;
    } else if(is_finished_move()) {
      pantheios::log_DEBUG("call update_move") ;
      remove_connection(id) ;
      thinker_manager* mgr = get_property<thinker_manager*>(thinker_manager::HAS_MANAGER, (thinker_manager*)0) ;
      if(mgr) 
	mgr->handle_message(make_message(name(), m_graph->name(), 0.0f,
					 m_graph->FIX_ROAD, false)) ;
      m_moves.clear() ;
      m_pos_id = -1 ;
    } else 
      update_move_state(time_elapsed) ;
  }

  bool game_map_mover::is_finished_move() {
    return m_pos_id == static_cast<int>(m_moves.size())-1 ;
  }

  void game_map_mover::update_move_state(float time_elapsed) {
    m_current_move_time += time_elapsed ;
    if(m_current_move_time > m_move_speed) {
      m_current_move_time -= m_move_speed ;
      m_pos_id ++ ;
      pantheios::log_DEBUG(pantheios::integer(m_pos_id), " vs ", pantheios::integer(m_moves.size())) ;
      set_position(m_graph->get_map_grid_position(m_moves[m_pos_id])) ;
    }
  }
}
